package main

import (
	"fmt"
	"time"
)

/**
通道，用于routine之间的数据传递
*/
func main() {
	// channel的基本使用
	useChannel()
	// channel之间的数据传递
	rwChannel()
	// channel的遍历操作
	rangeChannel()
	// channel的关闭操作
	closeChannel()
	// 通过channel实现routine之间同步
	channelSync()
	// channel 作为pool提供给多个routine使用
	channelPool()
}

/**
channel的基本使用
*/
func useChannel() {
	// 普通的channel使用
	message := make(chan string)
	go func() {
		message <- "ping"
	}()
	fmt.Println(message)
	msg := <-message
	fmt.Println(msg)

	// 带两个缓冲区的channel使用
	buffMsg := make(chan string, 2)

	buffMsg <- "Hello"
	buffMsg <- "Hello2"
	// dead lock
	//buffMsg <- "Hello3"

	fmt.Println(<-buffMsg)
	fmt.Println(<-buffMsg)
}

/**
channel的读写及函数调用
*/
func rwChannel() {
	pings := make(chan string, 1)
	pongs := make(chan string, 1)
	ping(pings, "sended message")
	fmt.Println(<-pings)
	ping(pings, "passed message")
	pong(pings, pongs)
	fmt.Println(<-pongs)
}

/**
chan <- 表示只能往channel里写入
*/
func ping(pings chan<- string, msg string) {
	pings <- msg
}

/**
<- chan 表示只能往channel里读出
chan <- 表示只能往channel里写入
*/
func pong(pings <-chan string, pongs chan<- string) {
	msg := <-pings
	pongs <- msg
}

/**
遍历channel
*/
func rangeChannel() {
	queue := make(chan string, 2)
	queue <- "one"
	queue <- "two"
	close(queue)
	for ele := range queue {
		fmt.Println("rangeChannel()", "Channel element", ele)
	}
}

/**
关闭channel
*/
func closeChannel() {
	jobs := make(chan int, 5)
	done := make(chan bool)

	go func() {
		for {
			j, more := <-jobs
			if more {
				fmt.Println("closeChannel()", "received jobs", j)
			} else {
				fmt.Println("closeChannel()", "receied all jobs")
				done <- true
				return
			}
		}
	}()

	for j := 0; j < 3; j++ {
		jobs <- j
		fmt.Println("closeChannel()", "send jobs", j)
	}
	close(jobs)
	// panic: send on closed channel
	//jobs <- 5
	fmt.Println("closeChannel()", "send done or not ?", <-done)
}

/**
channel作为routine之间的数据同步
*/
func channelSync() {
	done := make(chan bool, 1)
	go func(done chan<- bool) {
		fmt.Println("working...")
		time.Sleep(time.Second)
		fmt.Println("done")
		done <- true
	}(done)
	<-done
	fmt.Println("All done!")
}

/**
channel作为routine之间的消息队列
*/
func channelPool() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)
	for i := range [3]int{1, 2, 3} {
		go func(id int, jobs <-chan int, results chan<- int) {
			for j := range jobs {
				fmt.Println("Worker", id, "starts handle", j)
				time.Sleep(time.Second * 1)
				fmt.Println("Worker", id, "ends handle", j)
				results <- j * 2
			}
		}(i, jobs, results)
	}
	for j := 0; j < 10; j++ {
		jobs <- j
	}
	close(jobs)
	for j := 0; j < 10; j++ {
		fmt.Println("Result ", <-results)
	}
}
